package com.linkhub.oms.admin.modules.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.google.common.collect.Lists;
import com.linkhub.oms.admin.common.enums.CustomerMenuMappingStateEnum;
import com.linkhub.oms.admin.common.enums.TabTypeCustomerBizStatusMappingEnum;
import com.linkhub.oms.admin.common.exception.ExceptionFactory;
import com.linkhub.oms.admin.common.exception.OrderExceptionFactory;
import com.linkhub.oms.admin.common.exception.ShopExceptionFactory;
import com.linkhub.oms.admin.common.util.I18nMessageUtil;
import com.linkhub.oms.admin.modules.order.domain.dto.OrderFulfillmentExpenseDTO;
import com.linkhub.oms.admin.modules.order.domain.param.*;
import com.linkhub.oms.admin.modules.order.domain.param.ordersplit.OrderPackageParam;
import com.linkhub.oms.admin.modules.order.domain.param.ordersplit.OrderSplitParam;
import com.linkhub.oms.admin.modules.order.domain.param.ordersplit.OrderSplitRestoreParam;
import com.linkhub.oms.admin.modules.order.domain.param.ordersplit.PackageSkuParam;
import com.linkhub.oms.admin.modules.order.domain.vo.ManualOrderImportResultVO;
import com.linkhub.oms.admin.modules.order.domain.vo.OrderFulfillmentResultVO;
import com.linkhub.oms.admin.modules.order.domain.vo.OrderTabCountVO;
import com.linkhub.oms.admin.modules.order.domain.vo.SyncOrderVO;
import com.linkhub.oms.admin.modules.order.domain.vo.orderlist.OrderlistVO;
import com.linkhub.oms.admin.modules.order.domain.vo.orderpdf.OrderPdfVO;
import com.linkhub.oms.admin.modules.order.service.CustomerOrderBizService;
import com.linkhub.oms.admin.modules.order.service.OrderBizService;
import com.linkhub.oms.admin.modules.order.service.OrderExpenseBizService;
import com.linkhub.oms.admin.modules.order.service.OrderFileService;
import com.linkhub.oms.admin.modules.order.service.OrderInfoAssembleService;
import com.linkhub.oms.admin.modules.order.util.OrderMappingAssist;
import com.linkhub.oms.admin.modules.satoken.session.LhSessionContext;
import com.linkhub.oms.admin.modules.stock.service.StockBizService;
import com.linkhub.oms.admin.modules.stock.domain.dto.PreemptionDTO;
import com.linkhub.oms.admin.modules.stock.service.StockHandler;
import com.linkhub.oms.admin.modules.user.account.domain.dto.UserAccountDTO;
import com.linkhub.oms.admin.modules.user.account.domain.vo.UserAccountVO;
import com.linkhub.oms.admin.modules.user.account.service.IUserAccountService;
import com.linkhub.oms.admin.modules.user.accountflow.service.IUserAccountFlowBizService;
import com.linkhub.oms.common.constant.WmsInfoConstant;
import com.linkhub.oms.common.enums.IEnumConvert;
import com.linkhub.oms.common.enums.logistic.CountryCodeMappingEnum;
import com.linkhub.oms.common.enums.mp.*;
import com.linkhub.oms.common.exception.BizException;
import com.linkhub.oms.common.response.PageDTO;
import com.linkhub.oms.common.util.CacheKeyAssist;
import com.linkhub.oms.common.util.QtBeanUtil;
import com.linkhub.oms.common.util.QtBigDecimalUtil;
import com.linkhub.oms.common.util.QtStreamUtil;
import com.linkhub.oms.component.excel.util.EasyExcelUtil;
import com.linkhub.oms.component.mp.util.QtMybatisPlusUtil;
import com.linkhub.oms.component.redis.locker.DistributedLocker;
import com.linkhub.oms.dao.mapper.OrderEntityMapper;
import com.linkhub.oms.dao.mpservice.*;
import com.linkhub.oms.data.sync.api.shopify.domain.response.ShopOrderResponse;
import com.linkhub.oms.data.sync.service.ShopifyApiService;
import com.linkhub.oms.data.sync.service.ShopifyDataSyncBizService;
import com.linkhub.oms.data.sync.util.OrderAssist;
import com.linkhub.oms.data.sync.util.OrderQueryColumnAssist;
import com.linkhub.oms.entity.*;
import com.linkhub.oms.entity.resulttype.order.OrderInfoDO;
import com.linkhub.oms.entity.resulttype.order.OrderLocalProductDO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static com.linkhub.oms.admin.modules.order.constant.OrderConstant.SPLIT_SOURCE_ORDER_FLAG;
import static com.linkhub.oms.admin.modules.order.util.OrderMappingAssist.mappingOrderProductEntityList;
import static com.linkhub.oms.common.constant.ShopifyConstant.ORDER_DATA_TYPE_KEY;
import static com.linkhub.oms.common.enums.mp.CustomerBusinessStatusEnum.isPendingProcessed;
import com.linkhub.oms.data.sync.enums.OrderFinancialStatusEnum;

/**
 * @Description: CustomerOrderBizService
 * @Author: echo
 * @Date: 2024/3/31 15:27
 * @Version: 1.0
 */
@Slf4j
@Service
public class CustomerOrderBizServiceImpl implements CustomerOrderBizService {
    @Resource
    private IShopService shopService;
    @Resource
    private ShopifyDataSyncBizService shopifyDataSyncBizService;
    @Resource
    private IOrderService orderService;
    @Resource
    private OrderEntityMapper orderEntityMapper;
    @Resource
    private IOrderProductService orderProductService;
    @Resource
    private OrderInfoAssembleService orderInfoAssembleService;
    @Resource
    private IOrderAddressService orderAddressService;
    @Resource
    private DistributedLocker distributedLocker;
    @Resource
    private OrderBizService orderBizService;
    @Resource
    private ShopifyApiService shopifyApiService;
    @Resource
    private StockBizService stockBizService;
    @Resource
    private IUserAccountService userAccountService;
    @Resource
    private OrderExpenseBizService orderExpenseBizService;
    @Resource
    private IUserAccountFlowBizService userAccountFlowService;
    @Resource
    private StockHandler stockHandler;
    @Resource
    private ICountryPartitionService countryPartitionService;
    @Resource
    private OrderFileService orderFileService;
    @Resource
    private IShopProductSkuService shopProductSkuService;

    @Override
    public PageDTO<OrderlistVO> pageCustomerOrders( CustomerOrderQueryParam orderQueryParam ) {
        Integer tabType = orderQueryParam.getTabType();
        TabTypeCustomerBizStatusMappingEnum tabTypeCustomerBizStatusMapping = IEnumConvert.valueOf(tabType, TabTypeCustomerBizStatusMappingEnum.class);
        if (Objects.isNull(tabTypeCustomerBizStatusMapping)) {
            throw ExceptionFactory.getI18nBizException("validation.order.tabType.range");
        }
        CustomerBusinessStatusEnum customerBusinessStatus = tabTypeCustomerBizStatusMapping.getCustomerBusinessStatus();

        List<String> sysShopIds = getQueryShopIds(orderQueryParam);
        if (CollUtil.isEmpty(sysShopIds)) {
            return new PageDTO<>();
        }
        boolean pendingProcessed = Objects.equals(CustomerBusinessStatusEnum.PENDING_PROCESSED, customerBusinessStatus);
        boolean inPerformance = Objects.equals(CustomerBusinessStatusEnum.IN_PERFORMANCE, customerBusinessStatus);
        boolean tracking = Objects.equals(CustomerBusinessStatusEnum.TRACKING, customerBusinessStatus);
        CustomerOrderStatusEnum customerOrderStatus = null;
        if (inPerformance) {
            customerOrderStatus = IEnumConvert.valueOf(tabType, CustomerOrderStatusEnum.class);
        }

        String orderNumber = orderQueryParam.getOrderNumber();
        OrderStatusEnum orderStatus = IEnumConvert.valueOf(orderQueryParam.getOrderStatus(), OrderStatusEnum.class);

        Page<OrderEntity> page = orderService.lambdaQuery()
                .in(OrderEntity::getSysShopId, sysShopIds)
                .eq(OrderEntity::getCustomerBusinessStatus, customerBusinessStatus)
                .eq(Objects.nonNull(orderStatus), OrderEntity::getOrderStatus, orderStatus)
                .like(StringUtils.isNotBlank(orderNumber), OrderEntity::getOrderNumber, orderNumber)
                .eq(Objects.nonNull(customerOrderStatus), OrderEntity::getCustomerOrderStatus, customerOrderStatus)
                .eq(OrderEntity::getDataStatus, DataStatusEnum.ENABLE)
                // 只查询原拆分订单
                .eq(pendingProcessed, OrderEntity::getSourceOrderNumber, SPLIT_SOURCE_ORDER_FLAG)
                .orderByDesc(tracking, OrderEntity::getDeliveryTime)
                .orderByDesc(inPerformance, OrderEntity::getFulfillmentTime)
                .orderByDesc(OrderEntity::getCreatedAtConvert)
                .page(new Page<>(orderQueryParam.getPage(), orderQueryParam.getSize()));
        List<OrderEntity> records = page.getRecords();
        if (CollUtil.isEmpty(records)) {
            return QtMybatisPlusUtil.convertPage(page, null);
        }

        // 过滤出父拆分订单
        List<OrderEntity> splitOrders = QtStreamUtil.filter(records, OrderEntity::parentSplitOrder);
        List<OrderInfoDO> orders = orderInfoAssembleService.assembleOrderInfos(records);

        // 拆分订单的子订单处理
        fillSubOrders(splitOrders, orders);

        Map<String, OrderInfoDO> orderInfoMap = QtStreamUtil.toMap(orders, OrderInfoDO::getSysOrderId);
        return QtMybatisPlusUtil.convertPage(page,
                order -> OrderMappingAssist.mappingOrderlist(orderInfoMap.get(order.getSysOrderId())));
    }


    @Override
    public SyncOrderVO manualUpdateShopOrders( String userId ) {
        SyncOrderVO vo = new SyncOrderVO();
        int total = 0;
        List<ShopEntity> shops = shopService.listByUserId(userId, SuccessfulEnum.YES);
        if (CollUtil.isEmpty(shops)) {
            vo.setTotal(total);
            return vo;
        }
        for (ShopEntity shop : shops) {
            ShopOrderResponse response = shopifyDataSyncBizService.syncShopOrders(shop);
            total += response.count();

        }

        vo.setTotal(total);

        return vo;
    }

    @Override
    public void runPendingMatchOrders( String sysShopId ) {
        // 查询商店待匹配订单号
        List<OrderEntity> pendingMatchOrders = orderService.listShopOrders(sysShopId,
                CustomerBusinessStatusEnum.TO_BE_MATCHED);
        if (CollUtil.isEmpty(pendingMatchOrders)) {
            return;
        }
        List<String> sysOrderIds = QtStreamUtil.map(pendingMatchOrders, OrderEntity::getSysOrderId);

        // 查询待匹配订单行未全匹配的订单号
        List<String> unMatchSysOrderIds = orderProductService.listUnMatchSysOrderIds(sysOrderIds);
        Collection<String> matchSysOrderIds = CollUtil.subtract(sysOrderIds, unMatchSysOrderIds);
        List<OrderEntity> matchOrders = QtStreamUtil.filter(pendingMatchOrders,
                order -> matchSysOrderIds.contains(order.getSysOrderId()));
        if (CollUtil.isEmpty(matchOrders)) {
            return;
        }

        QtStreamUtil.peek(matchOrders, OrderAssist::fillOrderCustomerState);

        orderService.updateBatchById(matchOrders);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateOrderAddress( OrderAddressUpdateParam addressUpdateParam ) {
        OrderAddressUpdateParam param = addressUpdateParam;
        // 地址不能都为空
        if (StringUtils.isBlank(param.getAddress1()) && StringUtils.isBlank(param.getAddress2())) {
            throw ExceptionFactory.getI18nBizException("validation.address.notBlank");
        }

        // 地址变更时是否有变更邮编
        boolean isZipChangedFlag = false;

        OrderAddressEntity orderAddress = orderAddressService.getByOrderIds(param.getSysOrderId());
        if (Objects.isNull(orderAddress)) {
            OrderAddressEntity saveEntity = new OrderAddressEntity();
            QtBeanUtil.copyProperties(param, saveEntity, CopyOptions.create().ignoreNullValue());
            saveEntity.setUpdateFlag(BoolEnum.YES);
            saveEntity.setCreatedTime(LocalDateTime.now());
            saveEntity.setUpdateTime(LocalDateTime.now());
            orderAddressService.save(saveEntity);

        } else {
            isZipChangedFlag = !StringUtils.equals(param.getZip(),orderAddress.getZip());
            QtBeanUtil.copyProperties(param, orderAddress, CopyOptions.create().ignoreNullValue());
            orderAddress.setUpdateFlag(BoolEnum.YES);
            orderAddress.setCreatedTime(null);
            orderAddress.setUpdateTime(null);

            orderAddressService.updateById(orderAddress);

        }

        if (param.isCountryChangedFlag()) {
            orderBizService.resetOrderLogistic(param.getSysOrderId());
        } else if(isZipChangedFlag) {
            boolean existPartition = countryPartitionService.existPartitionOfCountry(param.getCountryCode());
            // 国家没改，邮编改了，且国家有分区
            if(existPartition){
                orderBizService.resetOrderLogistic(param.getSysOrderId());
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateOrderInfo( OrderInfoUpdateParam updateParam ) {
        OrderEntity update = new OrderEntity();
        update.setSellerNote(updateParam.getSellerNote());
        orderService.updateOrderInfo(updateParam.getSysOrderId(), update);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void splitOrder( OrderSplitParam splitParam ) {
        // 订单状态校验
        String sysOrderId = splitParam.getSysOrderId();
        String sysShopId = splitParam.getSysShopId();
        OrderInfoDO orderInfoDO = orderInfoAssembleService.assembleOrder(sysOrderId);
        OrderEntity order = orderInfoDO.getOrder();
        // 非待处理状态 或 已拆分订单不可拆分
        if (!CustomerBusinessStatusEnum.PENDING_PROCESSED.equals(order.getCustomerBusinessStatus())
                || BoolEnum.YES.equals(order.getSplitFlag())) {
            throw OrderExceptionFactory.getOrderSplitBizError();
        }

        // shopId加锁
        String lockKey = CacheKeyAssist.getShopifyDataSyncLockKey(sysShopId, ORDER_DATA_TYPE_KEY);
        try {
            if (!distributedLocker.tryLock(lockKey)) {
                throw ExceptionFactory.getI18nBizException("order.sync.concurrence.error");
            }
            // 查询订单商品
            List<OrderPackageParam> packages = splitParam.getPackages();
            List<OrderProductEntity> orderProducts = mappingOrderProductEntityList(orderInfoDO);

            // 对比拆分包裹数量
            checkPackageSkuCount(packages, orderProducts);

            Map<String, OrderProductEntity> orderSkuMap = QtStreamUtil.toMap(orderProducts, OrderProductEntity::getSkuId);
            // 新订单处理
            //- 一个包裹生成一个订单，非商品信息则复制原订单
            AtomicInteger index = new AtomicInteger(1);
            List<OrderEntity> subOrders = QtStreamUtil.map(packages, packageParam -> {
                int curIndex = index.getAndIncrement();
                String newOrderId = String.format("%s_%s", sysOrderId, curIndex);
                String newOrderNumber = String.format("%s_%s", order.getOrderNumber(), curIndex);
                return OrderMappingAssist.createSplitSubOrder(order, newOrderId, newOrderNumber, packageParam, orderSkuMap);
            });

            orderBizService.saveBatchOrders(subOrders);

            // 原订单处理
            OrderEntity update = new OrderEntity();
            update.setSplitFlag(BoolEnum.YES);
            update.setLocalization(BoolEnum.YES);
            orderService.updateOrderInfo(sysOrderId, update);
            orderProductService.deleteBySysOrderIds(Lists.newArrayList(sysOrderId));

        }finally {
            distributedLocker.unlock(lockKey);
        }


    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void restoreOrder( OrderSplitRestoreParam restoreParam ) {
        String sysOrderId = restoreParam.getSysOrderId();
        OrderEntity parentOrder = orderService.getByOrderId(sysOrderId);
        // 非待处理、拆分订单不可还原
        if (!isPendingProcessed(parentOrder.getCustomerBusinessStatus())
                || BoolEnum.NO.equals(parentOrder.getSplitFlag())) {
            throw OrderExceptionFactory.getSplitOrderRestoreError();

        }

        // 子订单为空或任一子订单状态非待处理不可还原
        List<OrderInfoDO> subOrders = orderInfoAssembleService.assembleSubOrders(Lists.newArrayList(sysOrderId));
        if (CollUtil.isEmpty(subOrders)
                || QtStreamUtil.anyMatch(subOrders, orderInfo ->
                !isPendingProcessed(orderInfo.getOrder().getCustomerBusinessStatus()))) {
            throw OrderExceptionFactory.getSplitOrderRestoreError();
        }
        // 根据skuId合并子订单本地产品
        List<OrderProductEntity> productList = mergeSubOrderSkus(sysOrderId, subOrders);
        orderProductService.saveBatch(productList);
        // 原订单处理
        OrderEntity update = new OrderEntity();
        update.setSplitFlag(BoolEnum.NO);
        update.setLocalization(BoolEnum.NO);
        orderService.updateOrderInfo(sysOrderId, update);

        orderBizService.resetOrderLogistic(sysOrderId);

        // 子订单处理
        // 删除所有子订单数据
        orderBizService.deleteOrders(QtStreamUtil.map(subOrders, OrderInfoDO::getSysOrderId));

    }


    @Override
    public List<OrderTabCountVO> queryOrderCount( CustomerOrderCountQueryParam countQueryParam ) {

        CustomerMenuMappingStateEnum bizStatus = IEnumConvert.valueOf(countQueryParam.getMenuId(),
                CustomerMenuMappingStateEnum.class);
        if (Objects.isNull(bizStatus)) {
            return Lists.newArrayListWithCapacity(0);
        }

        List<String> sysShopIds = countQueryParam.getSysShopIds();
        if (CollUtil.isEmpty(sysShopIds)) {
            return Lists.newArrayListWithCapacity(0);
        }
//
//        LambdaQueryWrapper<OrderEntity> lambdaQuery = Wrappers.lambdaQuery(OrderEntity.class);
//        lambdaQuery
//                .in(OrderEntity::getSysShopId, sysShopIds)
//                .in(OrderEntity::getCustomerBusinessStatus, bizStatus.getBizStatus())
//                .eq(OrderEntity::getDataStatus, DataStatusEnum.ENABLE)
//                .eq(Objects.equals(bizStatus, CustomerMenuMappingStateEnum.ORDER_LIST),
//                        OrderEntity::getSourceOrderNumber, SPLIT_SOURCE_ORDER_FLAG)
//                .groupBy(OrderEntity::getCustomerBusinessStatus);
//
//        QueryWrapper<OrderEntity> queryWrapper = WrapperConverter.convertLambdaCondition(lambdaQuery);
//        queryWrapper.select("Fcustomer_business_status, count(Fid) as count");
//
//        List<OrderEntity> orders = orderService.list(queryWrapper);

        SFunction<OrderEntity, ?> column = bizStatus.getColumn();
        MPJLambdaWrapper<OrderEntity> wrapper = JoinWrappers.lambda(OrderEntity.class);
        wrapper.select(column)
                // COUNT(t.Fid) AS count
                .selectCount(OrderEntity::getId, OrderEntity::getCount)
                .in(OrderEntity::getSysShopId, sysShopIds)
                .in(column, bizStatus.getBizStatus())
                // 履约中
                .eq(Objects.equals(bizStatus.getCode(), CustomerMenuMappingStateEnum.IN_PERFORMANCE.getCode()),
                        OrderEntity::getCustomerBusinessStatus, CustomerBusinessStatusEnum.IN_PERFORMANCE)
                .eq(OrderEntity::getDataStatus, DataStatusEnum.ENABLE)
                .eq(Objects.equals(bizStatus, CustomerMenuMappingStateEnum.ORDER_LIST),
                        OrderEntity::getSourceOrderNumber, SPLIT_SOURCE_ORDER_FLAG)
                .groupBy(column);

        List<OrderEntity> orders = orderService.listByJoinWrapper(wrapper);

        // 查询待发货列表订单数量，待发货状态为虚拟状态，实际在数据库中记录为履约中-有货、履约中-缺货，为以上两个状态的合集
        if (Objects.equals(bizStatus, CustomerMenuMappingStateEnum.ORDER_LIST)) {
            MPJLambdaWrapper<OrderEntity> wrapperWaitDeliver = JoinWrappers.lambda(OrderEntity.class);
            wrapperWaitDeliver.selectAs(String.valueOf(CustomerBusinessStatusEnum.WAIT_DELIVER.getCode()), OrderEntity::getCustomerBusinessStatus)
                    .selectCount(OrderEntity::getId, OrderEntity::getCount)
                    .in(OrderEntity::getSysShopId, sysShopIds)
                    .in(OrderEntity::getCustomerOrderStatus, CustomerMenuMappingStateEnum.IN_PERFORMANCE.getBizStatus())
                    .eq(OrderEntity::getCustomerBusinessStatus, CustomerBusinessStatusEnum.IN_PERFORMANCE)
                    .eq(OrderEntity::getDataStatus, DataStatusEnum.ENABLE)
                    .groupBy(String.format("'%s'", CustomerBusinessStatusEnum.WAIT_DELIVER.getCode()));

            List<OrderEntity> waitDeliverOrders = orderService.listByJoinWrapper(wrapperWaitDeliver);
            orders.addAll(waitDeliverOrders);
        }

        return QtStreamUtil.map(orders, OrderMappingAssist::mappingTabCount);
    }



    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderFulfillmentResultVO submitOrderFulfillments( OrderFulfillmentParam fulfillmentParam ) {

        List<OrderEntity> pendingSubmitOrders = filterPendingSubmitOrders(fulfillmentParam);
        if (CollUtil.isEmpty(pendingSubmitOrders)) {
            throw ExceptionFactory.getI18nBizException("order.submit.fulfillment.empty.error");
        }

        // 对比可提交履约订单是否有带更新数据
        boolean updateFlag = orderBizService.syncOrderIfNecessary(pendingSubmitOrders);

        if (updateFlag) {
            throw ExceptionFactory.getI18nBizException("order.submit.fulfillment.pending.sync.error");
        }

        List<String> sysShopIds = QtStreamUtil.map(fulfillmentParam.getShopOrders(), BaseSingleOrderParam::getSysShopId);
        List<String> multiLockKeys = QtStreamUtil.map(sysShopIds,
                sysShopId -> CacheKeyAssist.getShopifyDataSyncLockKey(sysShopId, ORDER_DATA_TYPE_KEY));
        // 加锁
        if (!distributedLocker.tryLockMulti(multiLockKeys)) {
            throw ExceptionFactory.getI18nBizException("order.sync.concurrence.error");
        }

        try {
            String userId = fulfillmentParam.getUserId();
            List<String> pendingOrderIds = QtStreamUtil.map(pendingSubmitOrders, OrderEntity::getSysOrderId);

            // 物流方式校验
            List<OrderEntity> orders = orderService.listBySysOrderIds(pendingOrderIds);
            int total = CollUtil.size(orders);
            Map<Boolean, List<OrderEntity>> logisticConfigMap = QtStreamUtil.partition(orders,
                    order -> StringUtils.isNotBlank(order.getChannelCode()));

            List<OrderFulfillmentExpenseDTO> fulfillmentExpenseList = Lists.newArrayList();
            // 订单运费、操作费冻结校验
            UserAccountVO userAccount = userAccountService.getUserAccount(userId);
            String availableBalance = userAccount.getAvailableBalance();
            Map<Boolean, List<OrderEntity>> orderExpenseMap = QtStreamUtil.partition(logisticConfigMap.get(true),
                    order -> {
                        BigDecimal curBalance = NumberUtil.toBigDecimal(userAccount.getAvailableBalance());
                        if (QtBigDecimalUtil.le(curBalance, BigDecimal.ZERO)) {
                            return false;
                        }
                        OrderFulfillmentExpenseDTO expenseDTO = orderExpenseBizService.calculateVat(order.getSysOrderId());
                        BigDecimal vat = expenseDTO.getVat();
                        BigDecimal handlingFee = expenseDTO.getHandlingFee();
                        BigDecimal estimatedFreight = QtBigDecimalUtil.defaultIfNull(order.getEstimatedFreight(),BigDecimal.ZERO);
                        BigDecimal registrationFreight = QtBigDecimalUtil.defaultIfNull(order.getRegistrationFreight(),BigDecimal.ZERO);
                        BigDecimal operatingCharge = orderExpenseBizService.operatingCharge(order.getSysOrderId());

                        BigDecimal orderExpense = NumberUtil.add(estimatedFreight, operatingCharge,registrationFreight,vat,handlingFee);
                        if (QtBigDecimalUtil.lt(curBalance, orderExpense)) {
                            return false;
                        }

                        userAccount.setAvailableBalance(QtBigDecimalUtil.toString(NumberUtil.sub(curBalance, orderExpense)));

                        expenseDTO.setSysOrderId(order.getSysOrderId());
                        expenseDTO.setEstimatedFreight(estimatedFreight);
                        expenseDTO.setRegistrationFreight(registrationFreight);
                        expenseDTO.setOperatingCharge(operatingCharge);

                        fulfillmentExpenseList.add(expenseDTO);
                        log.info("订单费用：{}",expenseDTO);
                        return true;
                    });

            List<String> couldSubmitOrderIds = QtStreamUtil.map(orderExpenseMap.get(true), OrderEntity::getSysOrderId);
            // 生成装箱单，并上传
            Map<Boolean,List<OrderPdfVO>> packagePdfUploadMap = orderFileService.createPackagePdfs(couldSubmitOrderIds);

            OrderFulfillmentResultVO resultVO = OrderFulfillmentResultVO.createResult(total,
                    logisticConfigMap.get(false),
                    orderExpenseMap.get(false),
                    packagePdfUploadMap.get(false));

            couldSubmitOrderIds = QtStreamUtil.map(packagePdfUploadMap.get(true), OrderPdfVO::getSysOrderId);
            if (CollUtil.isEmpty(couldSubmitOrderIds)) {
                // 返回失败原因，条数
                return resultVO;
            }
            // 冻结
            BigDecimal freezeCost = NumberUtil.sub(NumberUtil.toBigDecimal(availableBalance),
                    NumberUtil.toBigDecimal(userAccount.getAvailableBalance()));
            UserAccountDTO accountAmount = userAccountService.updateAccountAmount(userId, freezeCost, TransactionTypeEnum.FREEZE);

            // 资金流水
            List<UserAccountFlowEntity> accountFlows = Lists.newArrayList();
            for (OrderFulfillmentExpenseDTO expense : fulfillmentExpenseList) {
                UserAccountFlowEntity operatingChargeAccountFlow = expense.createOperatingChargeAccountFlow(userId, accountAmount.getTotalBalance());
                UserAccountFlowEntity estimatedFreightAccountFlow = expense.createEstimatedFreightAccountFlow(userId, accountAmount.getTotalBalance());
                UserAccountFlowEntity registrationFreightAccountFlow = expense.createRegistrationFreightAccountFlow(userId, accountAmount.getTotalBalance());

                accountFlows.add(operatingChargeAccountFlow);
                accountFlows.add(estimatedFreightAccountFlow);
                accountFlows.add(registrationFreightAccountFlow);

                if(QtBigDecimalUtil.isBigger(expense.getVat(),BigDecimal.ZERO)) {
                    UserAccountFlowEntity vatAccountFlow = expense.createVatAccountFlow(userId, accountAmount.getTotalBalance());
                    accountFlows.add(vatAccountFlow);
                }
                if(QtBigDecimalUtil.isBigger(expense.getHandlingFee(),BigDecimal.ZERO)) {
                    UserAccountFlowEntity vatHandlingFeeAccountFlow = expense.createVatHandlingFeeAccountFlow(userId, accountAmount.getTotalBalance());
                    accountFlows.add(vatHandlingFeeAccountFlow);
                }
            }
            userAccountFlowService.saveBatch(accountFlows);


            // 预占库存
            List<String> inStockOrderIds = Lists.newArrayList();
            Map<String, List<OrderProductEntity>> orderLocalSkuMap = orderInfoAssembleService.queryOrderLocalSkuIds(couldSubmitOrderIds);
            orderLocalSkuMap.forEach((orderId, orderProducts) -> {
                List<PreemptionDTO> preemptionDTOS = Lists.newArrayListWithCapacity(orderProducts.size());
                for (OrderProductEntity orderProduct : orderProducts) {
                    PreemptionDTO preemptionDTO = new PreemptionDTO();
                    preemptionDTO.setUserId(userId);
                    preemptionDTO.setStashName(WmsInfoConstant.WAREHOUSE_CODE);
                    preemptionDTO.setSkuId(orderProduct.getSkuId());
                    preemptionDTO.setSkuQuantity(orderProduct.getCurrentQuantity());
                    preemptionDTO.setBusinessType(WmsInfoConstant.XSDD);
                    preemptionDTO.setBusinessNo(orderProduct.getSysOrderId());
                    preemptionDTOS.add(preemptionDTO);
                }
                boolean preemptionSuccess = stockHandler.orderSubmitted(preemptionDTOS, false);
                if (preemptionSuccess) {
                    inStockOrderIds.add(orderId);
                }
            });

            // 提交履约
            orderService.submitFulfillments(couldSubmitOrderIds, inStockOrderIds);


            // 拆分原订单的子订单都不为待处理，则逻辑删除该原订单
            logicDeleteSplitOrderIfNecessary(pendingSubmitOrders, couldSubmitOrderIds);


            return resultVO;
        }finally {

            distributedLocker.unLockMulti(multiLockKeys);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void reviveProcess( BaseSingleOrderParam singleOrderParam ) {
        // 订单状态校验
        String sysOrderId = singleOrderParam.getSysOrderId();
        OrderEntity order = orderService.deepMappingByOrderId(sysOrderId);

        if (!Objects.equals(order.getOrderStatus(), OrderStatusEnum.REJECTED)) {
            throw ExceptionFactory.getI18nBizException("order.reviveProcess.error");
        }

        OrderEntity newOrder = copyOrder(sysOrderId, order);
        orderBizService.saveBatchOrders(Lists.newArrayList(newOrder));

        //- 原订单逻辑删除
        orderService.logicDeleteByOrderIds(Lists.newArrayList(sysOrderId));
    }

    @Override
    public void reSubmit(String userId, String skuId, String stashName) {
        // 查询缺货状态的订单
        MPJLambdaWrapper<OrderEntity> orderEntityWrapper = JoinWrappers.lambda(OrderEntity.class);
        orderEntityWrapper.selectAs(LocalProductEntity::getUserId, PreemptionDTO::getUserId)
                .selectAs(LocalProductEntity::getSkuId, PreemptionDTO::getSkuId)
                .selectAs(OrderProductEntity::getCurrentQuantity, PreemptionDTO::getSkuQuantity)
                .selectAs(OrderEntity::getSysOrderId, PreemptionDTO::getBusinessNo)
                .innerJoin(OrderProductEntity.class, on -> on.eq(OrderProductEntity::getSysOrderId, OrderEntity::getSysOrderId))
                .innerJoin(ShopProductSkuMappingEntity.class, on -> on.eq(ShopProductSkuMappingEntity::getShopSkuId, OrderProductEntity::getShopSkuId))
                .innerJoin(LocalProductEntity.class, on -> on.eq(ShopProductSkuMappingEntity::getSkuId, LocalProductEntity::getSkuId))
                .eq(OrderEntity::getCustomerOrderStatus, CustomerOrderStatusEnum.OUT_OF_STOCK.getCode())
                .eq(OrderEntity::getEmployeeOrderStatus, EmployeeOrderStatusEnum.OUT_OF_STOCK.getCode())
                .eq(LocalProductEntity::getUserId, userId)
                .eq(LocalProductEntity::getSkuId, skuId)
                .gt(OrderProductEntity::getCurrentQuantity, 0)
                .orderByAsc(OrderEntity::getCreatedTime);
        List<PreemptionDTO> preemptionDTOS = orderEntityMapper.selectJoinList(PreemptionDTO.class, orderEntityWrapper);
        log.info("待重新预占的sku数：{}", preemptionDTOS.size());
        if (CollUtil.isNotEmpty(preemptionDTOS)) {
            Map<String, List<PreemptionDTO>> grouped = QtStreamUtil.group(preemptionDTOS, PreemptionDTO::getBusinessNo);
            log.info("开始重新预占，待重新预占订单数：{}", grouped.keySet().size());
            grouped.forEach((orderId, pts) -> {
                boolean preemptionSuccess = stockHandler.orderSubmitted(pts, true);
                if (preemptionSuccess) {    // 重新预占成功
                    log.info("订单：{} 重新预占成功", orderId);
                    // 更新订单状态为有货
                    boolean updateSuccess = orderService.updateOrderStatus(orderId,
                            CustomerOrderStatusEnum.OUT_OF_STOCK, CustomerOrderStatusEnum.IN_STOCK,
                            EmployeeOrderStatusEnum.OUT_OF_STOCK, EmployeeOrderStatusEnum.IN_STOCK,
                            OrderStockStatusEnum.OUT_OF_STOCK, OrderStockStatusEnum.IN_STOCK);
                    log.info("订单状态更新结果，订单id: {}, {}", orderId, updateSuccess);
                }
            });
        }
    }

    @Override
    public void manualCreate( ManualCreateOrderParam manualCreateOrderParam ) {
        // 校验订单号是否已存在
        String orderNumber = manualCreateOrderParam.getOrderInfo().getOrderNumber();
        String sysShopId = manualCreateOrderParam.getOrderInfo().getSysShopId();
        OrderEntity orderNumberEntity = orderService.getByOrderNumber(sysShopId, orderNumber);
        if (orderNumberEntity != null) {
            throw new BizException(I18nMessageUtil.getMessage("order.create.error.orderNumberExists", orderNumber));
        }

        List<Long> shopSkuIds = manualCreateOrderParam.getProductList()
                .stream()
                .map(ManualCreateOrderParam.ProductInfo::getShopSkuId)
                .collect(Collectors.toList());
        // 查找订单商品已匹配记录
        List<Long> matchShopSkuIds = orderProductService.listMatchShopSkuIds(sysShopId, shopSkuIds);
        OrderEntity orderEntity = OrderAssist.ConvertManualOrder(sysShopId, matchShopSkuIds, manualCreateOrderParam);

        // 保存订单
        orderService.save(orderEntity);
        orderProductService.saveBatch(orderEntity.getOrderLineItems());
        orderAddressService.save(orderEntity.getOrderAddress());
    }

    @Override
    public ManualOrderImportResultVO importManualOrders( String userId, MultipartFile manualOrderExcel ) {
        ManualOrderImportResultVO manualOrderImportResultVO = new ManualOrderImportResultVO();
        List<ManualOrderImportResultVO.ManualOrderImportFailedResult> failList = new ArrayList<>();
        EasyExcelUtil.isValidFile(manualOrderExcel);

        String lastOrder = null;
        ManualImportOrderParam manualImportOrderParam = null;
        int successTotal = 0;
        try {
            // 使用 Hutool 提供的 ExcelReader 来读取 Excel 文件
            ExcelReader reader = ExcelUtil.getReader(manualOrderExcel.getInputStream(), "Import template"); // 指定工作表名称

            // 读取所有数据，返回 List<Map<String, Object>>，每个 Map 对应一行数据
            List<Map<String, Object>> rows = reader.readAll();

            // 遍历每一行数据
            for (Map<String, Object> row : rows) {
                String orderNumber = Objects.toString(row.get("* Order Number"), "");
                String storeName = Objects.toString(row.get("* Store Name"), "");
                String currentOrder = storeName + orderNumber;
                try {
                    // 订单第一行逻辑
                    if (StringUtils.isBlank(orderNumber) || StringUtils.isBlank(storeName) || !currentOrder.equals(lastOrder)) {
                        // 校验保存上一个订单信息
                        boolean isSuccess = checkAndSave(userId, manualImportOrderParam, failList);
                        if (isSuccess) {
                            successTotal++;
                        }

                        manualImportOrderParam = new ManualImportOrderParam();
                        String currency = StringUtils.defaultIfBlank(Objects.toString(row.get("Currency \n(Default USD)"), ""), CurrencyEnum.USD.getCode());

                        // 填充 OrderInfo
                        ManualImportOrderParam.OrderInfo orderInfo = new ManualImportOrderParam.OrderInfo();
                        orderInfo.setOrderNumber(orderNumber);
                        orderInfo.setShopName(storeName);
                        try {
                            orderInfo.setSellFreight(new BigDecimal(StringUtils.defaultIfBlank(Objects.toString(row.get("Total Freight"), ""), "0.0")));
                        } catch (Exception e) {
                            orderInfo.setSellFreight(null);
                        }
                        orderInfo.setCurrency(currency);
                        orderInfo.setPaymentStatus(StringUtils.defaultIfBlank(Objects.toString(row.get("Payment Status\n(Default paid)"), ""), OrderFinancialStatusEnum.PAID.getStatus()));
                        orderInfo.setShippingMethod(Objects.toString(row.get("Buyer's Designated Logistics"), ""));
                        orderInfo.setStash(StringUtils.defaultIfBlank(Objects.toString(row.get("Delivery Warehouse"), ""), WarehouseEnum.MICRO_WAREHOUSE.getDesc()));
                        orderInfo.setEmail(Objects.toString(row.get("E-mail"), ""));
                        orderInfo.setBuyerNote(Objects.toString(row.get("Buyer Remark"), ""));
                        orderInfo.setSellerNote(Objects.toString(row.get("Seller Remark"), ""));
                        orderInfo.setCreatedAt(StringUtils.defaultIfBlank(Objects.toString(row.get("Order Time"), ""), LocalDateTimeUtil.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss")));

                        // 填充 AddressInfo
                        ManualImportOrderParam.AddressInfo addressInfo = new ManualImportOrderParam.AddressInfo();
                        addressInfo.setName(Objects.toString(row.get("* Buyer's name"), ""));
                        addressInfo.setPhone(Objects.toString(row.get("* Phone"), ""));
                        addressInfo.setCity(Objects.toString(row.get("* City"), ""));
                        addressInfo.setZip(Objects.toString(row.get("* Postal Code"), ""));
                        addressInfo.setProvince(Objects.toString(row.get("* Province/State"), ""));
                        addressInfo.setCountryCode(Objects.toString(row.get("* Country Code"), ""));
                        addressInfo.setAddress1(Objects.toString(row.get("* Address 1"), ""));
                        addressInfo.setAddress2(Objects.toString(row.get("Address 2"), ""));
                        addressInfo.setCompany(Objects.toString(row.get("Company"), ""));

                        // 填充 ProductInfo
                        List<ManualImportOrderParam.ProductInfo> productList = new ArrayList<>();
                        ManualImportOrderParam.ProductInfo productInfo = new ManualImportOrderParam.ProductInfo();
                        productInfo.setShopSku(Objects.toString(row.get("* Product SKU"), ""));
                        productInfo.setCurrencyCode(currency); // 默认币种为 USD
                        try {
                            productInfo.setPrice(new BigDecimal(Objects.toString(row.get("* Unit Price"), null)));
                        } catch (Exception e) {
                            productInfo.setPrice(null);
                        }
                        try {
                            productInfo.setCurrentQuantity(Integer.parseInt(Objects.toString(row.get("* Quantity\n(An integer greater than 0)"), null)));
                        } catch (Exception e) {
                            productInfo.setCurrentQuantity(null);
                        }
                        // 将产品信息添加到列表中
                        productList.add(productInfo);

                        // 设置 ManualImportOrderParam 对象的值
                        manualImportOrderParam.setOrderInfo(orderInfo);
                        manualImportOrderParam.setAddressInfo(addressInfo);
                        manualImportOrderParam.setProductList(productList);
                    } else {
                        // 订单非第一行（商品信息行）逻辑
                        // 填充 ProductInfo
                        ManualImportOrderParam.ProductInfo productInfo = new ManualImportOrderParam.ProductInfo();
                        productInfo.setShopSku(Objects.toString(row.get("* Product SKU"), ""));
                        productInfo.setCurrencyCode(manualImportOrderParam.getProductList().get(0).getCurrencyCode());
                        try {
                            productInfo.setPrice(new BigDecimal(Objects.toString(row.get("* Unit Price"), null)));
                        } catch (Exception e) {
                            productInfo.setPrice(null);
                        }
                        try {
                            productInfo.setCurrentQuantity(Integer.parseInt(Objects.toString(row.get("* Quantity\n(An integer greater than 0)"), null)));
                        } catch (Exception e) {
                            productInfo.setCurrentQuantity(null);
                        }
                        // 将产品信息添加到列表中
                        manualImportOrderParam.getProductList().add(productInfo);
                    }
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                } finally {
                    lastOrder = currentOrder;
                }
            }
            // 校验保存最后一个订单信息
            boolean isSuccess = checkAndSave(userId, manualImportOrderParam, failList);
            if (isSuccess) {
                successTotal++;
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new RuntimeException("Failed to parse Excel file.");
        }
        manualOrderImportResultVO.setFailList(failList);
        manualOrderImportResultVO.setFailTotal(failList.size());
        manualOrderImportResultVO.setSuccessTotal(successTotal);
        return manualOrderImportResultVO;
    }

    private boolean checkAndSave( String userId, ManualImportOrderParam manualImportOrderParam, List<ManualOrderImportResultVO.ManualOrderImportFailedResult> failList ) {
        ManualOrderImportResultVO.ManualOrderImportFailedResult manualOrderImportFailedResult = new ManualOrderImportResultVO.ManualOrderImportFailedResult();
        try {
            if (manualImportOrderParam == null) {
                return false;
            }
            String shopName = manualImportOrderParam.getOrderInfo().getShopName();
            String orderNumber = manualImportOrderParam.getOrderInfo().getOrderNumber();
            manualOrderImportFailedResult.setOrderNumber(orderNumber);
            manualOrderImportFailedResult.setShopName(shopName);

            // 只有已付款订单才支持导入
            if (!OrderFinancialStatusEnum.PAID.getStatus().equals(manualImportOrderParam.getOrderInfo().getPaymentStatus())) {
                String message = "Only paid orders can be imported";
                generateFailResult(message, manualOrderImportFailedResult, failList);
                return false;
            }
            // 商店是否存在
            ShopEntity shopEntity = shopService.getUserShopByShopName(userId, shopName);
            // 商店不存在
            if (shopEntity == null) {
                String message = "Store \"" + shopName + "\" does not exist";
                generateFailResult(message, manualOrderImportFailedResult, failList);
                return false;
            }
            // 商店非shipo商店
            if (!PlatFormEnum.SHIPO.equals(shopEntity.getPlatForm())) {
                String message = "The store \"" + shopName + "\" is not a shipo platform store";
                generateFailResult(message, manualOrderImportFailedResult, failList);
                return false;
            }
            String sysShopId = shopEntity.getSysShopId();
            manualImportOrderParam.getOrderInfo().setSysShopId(sysShopId);
            // 订单是否已存在
            OrderEntity existOrderEntity = orderService.getByOrderNumber(sysShopId, orderNumber);
            if (existOrderEntity != null) {
                String message = "The order number \"" + orderNumber + "\" already exists";
                generateFailResult(message, manualOrderImportFailedResult, failList);
                return false;
            }
            // 同一订单是否有重复SKU
            List<ManualImportOrderParam.ProductInfo> productList = manualImportOrderParam.getProductList();
            boolean hasDuplicateSku = productList.stream()
                    .collect(Collectors.groupingBy(ManualImportOrderParam.ProductInfo::getShopSku, Collectors.counting()))
                    .values()
                    .stream()
                    .anyMatch(count -> count > 1);
            if (hasDuplicateSku) {
                // 有重复的SKU
                String message = "The order has duplicate product SKU";
                generateFailResult(message, manualOrderImportFailedResult, failList);
                return false;
            }
            // 产品是否存在
            for (ManualImportOrderParam.ProductInfo productInfo : productList) {
                String sku = productInfo.getShopSku();
                ShopProductSkuEntity shopProductBysku = shopProductSkuService.getShopProductBysku(sysShopId, sku);
                if (shopProductBysku == null) {
                    // 产品不存在
                    String message = "The product sku \"" + sku + "\" does not exist";
                    generateFailResult(message, manualOrderImportFailedResult, failList);
                    return false;
                }
                productInfo.setShopProductId(shopProductBysku.getProductId());
                productInfo.setShopSkuId(shopProductBysku.getSkuId());
            }

            // 校验所有参数
            ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
            Validator validator = factory.getValidator();
            // 进行验证
            Set<ConstraintViolation<ManualImportOrderParam>> violations = validator.validate(manualImportOrderParam);
            // 如果有验证失败，输出错误信息
            if (!violations.isEmpty()) {
                // 获取所有的错误信息，并用分号连接
                String message = violations.stream()
                        .map(violation -> violation.getMessage())
                        .distinct()
                        .collect(Collectors.joining("; "));

                generateFailResult(message, manualOrderImportFailedResult, failList);
                return false;
            }

            // 设置国家
            String countryCode = manualImportOrderParam.getAddressInfo().getCountryCode();
            CountryCodeMappingEnum countryCodeMappingEnum = CountryCodeMappingEnum.getByCountryCode(countryCode);
            manualImportOrderParam.getAddressInfo().setCountry(countryCodeMappingEnum != null ? countryCodeMappingEnum.getEnCountry() : countryCode);

            // 保存订单
            ManualCreateOrderParam manualCreateOrderParam = new ManualCreateOrderParam();
            QtBeanUtil.copyProperties(manualImportOrderParam, manualCreateOrderParam);
            List<Long> shopSkuIds = manualCreateOrderParam.getProductList()
                    .stream()
                    .map(ManualCreateOrderParam.ProductInfo::getShopSkuId)
                    .collect(Collectors.toList());
            // 查找订单商品已匹配记录
            List<Long> matchShopSkuIds = orderProductService.listMatchShopSkuIds(sysShopId, shopSkuIds);
            OrderEntity orderEntity = OrderAssist.ConvertManualOrder(sysShopId, matchShopSkuIds, manualCreateOrderParam);
            // 保存订单
            orderService.save(orderEntity);
            orderProductService.saveBatch(orderEntity.getOrderLineItems());
            orderAddressService.save(orderEntity.getOrderAddress());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            generateFailResult(e.getMessage(), manualOrderImportFailedResult, failList);
            return false;
        }
        return true;
    }

    private void generateFailResult( String message, ManualOrderImportResultVO.ManualOrderImportFailedResult manualOrderImportFailedResult, List<ManualOrderImportResultVO.ManualOrderImportFailedResult> failList ) {
        manualOrderImportFailedResult.setMessage(message);
        failList.add(manualOrderImportFailedResult);
    }

    private void fillSubOrders(List<OrderEntity> splitOrders, List<OrderInfoDO> orders ) {
        if (CollUtil.isEmpty(splitOrders)) {
            return;
        }

        List<String> orderIds = QtStreamUtil.map(splitOrders, OrderEntity::getSysOrderId);

        List<OrderInfoDO> subOrderInfoDOList = assembleSubOrders(orderIds);
        Map<String, List<OrderInfoDO>> orderGroupMap = QtStreamUtil.group(subOrderInfoDOList,
                subOrder -> subOrder.getOrder().getSourceOrderNumber());

        for (OrderInfoDO order : orders) {
            if (orderGroupMap.containsKey(order.getSysOrderId())) {
                order.setSubOrders(orderGroupMap.get(order.getSysOrderId()));
            }
        }
    }

    private List<OrderInfoDO> assembleSubOrders( List<String> orderIds ) {
        return orderInfoAssembleService.assembleSubOrders(orderIds);
    }

    private List<String> getQueryShopIds( CustomerOrderQueryParam orderQueryParam ) {
        List<String> sysShopIds = orderQueryParam.getSysShopIds();
        if (CollUtil.isEmpty(sysShopIds)) {
            return LhSessionContext.getUserShopIds();
        }
        if (!LhSessionContext.checkLoginUserShops(sysShopIds)) {
            throw ShopExceptionFactory.getSysShopIdIllegality();
        }

        return sysShopIds;
    }


    private void checkPackageSkuCount( List<OrderPackageParam> packages, List<OrderProductEntity> orderProducts ) {
        Map<String, Integer> skuSumMap = packages
                .stream()
                .flatMap(param -> param.getPackageSkuList().stream())
                .collect(Collectors.groupingBy(PackageSkuParam::getLocalSkuId,
                        Collectors.summingInt(PackageSkuParam::getCount)));

        Map<String, Integer> aggregatedQuantities = orderProducts.stream()
                .collect(Collectors.groupingBy(
                        OrderProductEntity::getSkuId,
                        Collectors.summingInt(OrderProductEntity::getCurrentQuantity)
                ));
        boolean skuCountError = skuSumMap.equals(aggregatedQuantities);
//        boolean skuCountError = QtStreamUtil.anyMatch(orderProducts,
//                orderProduct -> !orderProduct.getCurrentQuantity().equals(skuSumMap.get(orderProduct.getSkuId())));
        if (!skuCountError) {
            throw OrderExceptionFactory.getOrderSplitSkuError();
        }
    }

    private List<OrderProductEntity> mergeSubOrderSkus( String sysOrderId, List<OrderInfoDO> subOrders ) {
        // 合并子订单的本地商品信息
        List<OrderLocalProductDO> orderLocalProducts = QtStreamUtil.flatMap(subOrders,
                order -> order.getOrderLocalProducts().stream());

        Map<String, List<OrderLocalProductDO>> skuMap = orderLocalProducts.stream()
                .collect(Collectors.groupingBy(
                        product -> product.getSkuId() + product.getShopSkuId()
                ));

        List<OrderProductEntity> productList = Lists.newArrayListWithCapacity(skuMap.size());
        for (Map.Entry<String, List<OrderLocalProductDO>> entry : skuMap.entrySet()) {
            List<OrderLocalProductDO> products = entry.getValue();
            Integer skuCount = products.stream()
                    .map(OrderLocalProductDO::getCurrentQuantity)
                    .reduce(0, Integer::sum);
            OrderProductEntity orderProductEntity = OrderMappingAssist.mappingOrderLocalProduct(products.get(0));
            orderProductEntity.setSysOrderId(sysOrderId);
            orderProductEntity.setCurrentQuantity(skuCount);
            productList.add(orderProductEntity);
        }
        return productList;
    }

    private void logicDeleteSplitOrderIfNecessary( List<OrderEntity> pendingSubmitOrders, List<String> couldSubmitOrderIds ) {
        // 获取已提交履约的拆分子订单
        List<String> sourceSysOrderIds = QtStreamUtil.filterAndMapAndDistinct(pendingSubmitOrders,
                submitOrder -> couldSubmitOrderIds.contains(submitOrder.getSysOrderId())
                        && !SPLIT_SOURCE_ORDER_FLAG.equals(submitOrder.getSourceOrderNumber()),
                OrderEntity::getSourceOrderNumber);

        // 获取所有sourceNumber
        // 查询状态为待处理的、sourceNumber
        if (CollUtil.isNotEmpty(sourceSysOrderIds)) {

            List<OrderEntity> pendingProcessedSubOrders = orderService.listPendingProcessedSubOrders(sourceSysOrderIds);
            List<String> pendingProcessSourceOrderIds = QtStreamUtil.map(pendingProcessedSubOrders, OrderEntity::getSourceOrderNumber);
            // 逻辑删除空壳拆分原订单
            sourceSysOrderIds.removeAll(pendingProcessSourceOrderIds);
            orderService.logicDeleteByOrderIds(sourceSysOrderIds);

        }
    }

    private List<OrderEntity> filterPendingSubmitOrders( OrderFulfillmentParam fulfillmentParam ) {
        List<BaseSingleOrderParam> shopOrders = fulfillmentParam.getShopOrders();
        List<String> sysOrderIds = QtStreamUtil.mapAndDistinct(shopOrders, BaseSingleOrderParam::getSysOrderId);
        List<String> sysShopIds = QtStreamUtil.mapAndDistinct(shopOrders, BaseSingleOrderParam::getSysShopId);

        List<OrderEntity> orders = orderService.listShopOrders(sysShopIds,
                sysOrderIds, OrderQueryColumnAssist.queryOrderFulfillmentColumns());

        List<OrderEntity> pendingSubmitOrders = QtStreamUtil.filter(orders,
                // 待处理订单
                order -> isPendingProcessed(order.getCustomerBusinessStatus())
                        // 非拆分订单或拆分订单的子订单
                        && (Objects.equals(order.getSplitFlag(), BoolEnum.NO)
                        || !SPLIT_SOURCE_ORDER_FLAG.equals(order.getSourceOrderNumber())));
        return pendingSubmitOrders;
    }

    private OrderEntity copyOrder( String sysOrderId, OrderEntity order ) {
        //- 复制原订单，生成新订单
        OrderEntity newOrder = new OrderEntity();
        BeanUtil.copyProperties(order, newOrder);
        String newSysOrderIds = IdUtil.getSnowflake().nextIdStr();
        newOrder.setSysOrderId(newSysOrderIds);
        newOrder.setRefusalReason(null);
        newOrder.setFulfillmentTime(null);
        newOrder.setDeliveryTime(null);
        OrderAssist.fillOrderState(newOrder, Lists.newArrayListWithCapacity(0), true);
        newOrder.setCustomerBusinessStatus(CustomerBusinessStatusEnum.PENDING_PROCESSED);
        newOrder.setCustomerOrderStatus(CustomerOrderStatusEnum.VOID);
        newOrder.setOrderStockStatus(OrderStockStatusEnum.VOID);
        newOrder.setEmployeeBusinessStatus(EmployeeBusinessStatusEnum.CUSTOMER_NOT_PERFORMING);
        newOrder.setEmployeeOrderStatus(EmployeeOrderStatusEnum.VOID);
        newOrder.setSplitFlag(BoolEnum.NO);
        newOrder.setSourceOrderNumber(SPLIT_SOURCE_ORDER_FLAG);
        newOrder.setLocalization(BoolEnum.NO);
        newOrder.setDataStatus(DataStatusEnum.ENABLE);
        newOrder.setCreatedTime(LocalDateTime.now());
        newOrder.setUpdateTime(LocalDateTime.now());
        newOrder.getOrderAddress().setSysOrderId(newSysOrderIds);
        // 查询订单商品信息
        List<OrderProductEntity> orderProducts = orderProductService.listBySysOrderIds(Lists.newArrayList(sysOrderId));
        QtStreamUtil.peek(orderProducts, orderProduct -> orderProduct.setSysOrderId(newSysOrderIds));
        newOrder.setOrderLineItems(orderProducts);
        newOrder.setChannelCode("");
        newOrder.setEstimatedFreight(null);
        newOrder.setRegistrationFreight(null);
        return newOrder;
    }


}
